// 请求方法类型
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD' | 'TRACE' | 'CONNECT';

// 响应数据类型
export interface Response<T> {
    code: number;
    message: string;
    data: T;
}
// 请求选项类型
export interface RequestOptions {
    headers?: Record<string, string>;
    timeout?: number;
    dataType?: string;
    responseType?: string;
    // 是否请求前校验是否登录
    checkLogin?: boolean;
}
// 请求工具类
function request<T>(
    method: HttpMethod, 
    url: string, 
    data: any, 
    other: RequestOptions = {}
): Promise<Response<T>> {
    return new Promise((resolve, reject) => {
        const { headers, timeout, dataType, responseType, checkLogin } = other;
        uni.request({
            url: url,
            method: method,
            data: data,
            timeout: timeout || 60 * 1000,
            headers: headers || {},
            dataType: dataType || 'json',
            responseType: responseType || 'text',
            checkLogin: checkLogin || false,
            success: (res: any) => {
                console.log('request success: ', res);
                const codeStatus = res.statusCode;
                // 用户未登录时
                if(codeStatus === 401) {
                    uni.redirectTo({
                        url: '/pages-sub/login/index',
                    });
                    return reject({
                        message: '请先登录',
                    });
                } 
                // 用户没有权限访问时
                else if(codeStatus === 403) {
                    uni.redirectTo({
                        url: '/pages-sub/exceptions/403',
                    });
                    return reject({
                        message: '暂无权限',
                    });
                }
                const code = res.data.code;
                // 有返回是code不为200时，则认为请求失败
                if(code !== 200) {
                    uni.showToast({
                        title: res.data.message,
                        icon: 'none',
                    });
                    return reject(res.data);
                }
                resolve(res.data);
            },
            fail: (err: any) => {
                console.log('request fail: ', err);
                if(err.errMsg.includes('timeout')) {
                    uni.showToast({
                        title: '请求超时',
                        icon: 'none',
                    });
                } else if(err.errMsg.includes('request:fail')) {
                    uni.showToast({
                        title: '网络异常，请稍后再试',
                        icon: 'none',
                    });
                }
                reject(err);
            }
        });
    })
}

const httpMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD', 'TRACE', 'CONNECT'];
const http: Record<string, <T = any>(url: string, data: any, other: any) => Promise<Response<T>>> = {};
httpMethods.forEach((key: string) => {
    http[key.toLowerCase() as keyof typeof http] = <T = any>(url: string, data: any, other: any) => {
        return request<T>(key, url, data, other);
    }
});
export default http;    
